home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- MASTERMIND player. 10 digits (0-9); words of length ln (= 2..6).
-
- Makefile is not provided: it's too easy to compile!
-
- compile like this: g++ -O -s -o mastermind mastermind.c -lncurses
-
- As you can see, it requires ncurses. If you don't have this library -
- get it, it's free! On the other hand, you might have curses
- instead. Comment out the #include <ncurses/ncurses.h> line, uncomment
- the next line (#include <curses.h>) and compile like this:
-
- g++ -O -s -o mastermind mastermind.c -lcurses -ltermcap
-
- Change Log:
-
- 1.3 Dec 20 1994. The word length is not a constant anymore. The
- players are timed. The code is cleaned up quite a bit. It should be
- faster now if you have an FPU.
-
- 1.2 Dec 12 1994. Added demo game, menus etc.
-
- 1.1 Nov 27 1994. Made the guesses to be "random" numbers. Some sort
- of support for curses added.
-
- 1.0 Nov 18 1994. First written.
-
- Copyright (C) 1994 by Semion D. Shteingold, <shteingd@math.ucla.edu>
- Comments, suggestions, bug reports/fixes, flame, praise are welcome!
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with This program; see the file COPYING. If not, write to the
- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- ***********************************************************************/
-
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <sys/time.h>
- #include <math.h>
- #include <unistd.h>
- #include <ncurses/ncurses.h>
- //#include <curses.h> // If you do not have ncurses, uncomment this.
- #define MLN 6 // Maximal Length of the Number
- #define DEFLN 4 // DEFault Length of the Number
- #define GL 20 // Maximal Length of the Game
- #define VERSION "1.3"
- #define NUM2STR(num, st) sprintf (st, "%.*d", ln, num)
- /* Can you believe that sprintf returns <int strlen (st)> on Linux and
- Solaris and <char * st> on SunOS?! */
- #define MINIHELP "\tq,x: quit;\th,?: help;\tb. <- cursor -> f,\t\t"
- #define LEFTMARGIN 5
- #define FIRST 15 // first column
- #define SECOND 55 // second column
- #define SPACE 10 // dist from *'s to the replies
- #define BSPACE 14 // dist from *'s to the beginning of the decsiption
- #define HELPCOL 22 // the start of help in the first line
- #define MSGL (LINES-2) // MeSsaGe Line
- #define ASKL (LINES-2) // ASK Line
- #define HLPL (LINES-HLPLEN-3) // HeLP Line
- #define HLPLEN 7 // Number of lines for help
- #define MHL (LINES-1) // MiniHelp Line
- #define STARTL 2 // START the game from Line...
- #define CLN_STR(a) { move (a, 0); clrtoeol (); }
- #define MOVE_LEFT \
- CLN_STR(MSGL); pos = (pos-1+ln)%ln; move (x, y+pos); refresh()
- #define MOVE_RIGHT \
- CLN_STR(MSGL); pos = (pos+1)%ln; move (x, y+pos); refresh()
- #define MOVE_UP \
- CLN_STR(MSGL); pos = (pos-1+num)%num; move(pos+STARTL,LEFTMARGIN); refresh()
- #define MOVE_DOWN \
- CLN_STR(MSGL); pos = (pos+1)%num; move (pos+STARTL, LEFTMARGIN); refresh()
- #define MOVE_HOME_UP \
- CLN_STR(MSGL); pos = 0; move (pos+STARTL, LEFTMARGIN); refresh()
- #define MOVE_HOME_LEFT \
- CLN_STR(MSGL); pos = 0; move (x, y+pos); refresh()
- #define MOVE_END_DOWN \
- CLN_STR(MSGL); pos = num-1; move (pos+STARTL, LEFTMARGIN); refresh()
- #define MOVE_END_RIGHT \
- CLN_STR(MSGL); pos = ln-1; move (x, y+pos); refresh()
- #define PUT_HELP(text) {move(0,HELPCOL); clrtoeol(); addstr(text); refresh();}
- #define GET_HELP(a) CLN_STR(MSGL); help (a); refresh(); break
- #define PUT_STARS(x, y) \
- { move(x, y); for(int i=0;i<ln;i++) addch('*'); move(x,y); refresh();}
- #define RND(n) ( (int) (drand48() * (n)))
- #ifdef _CURSES_H
- #define BEEP addch (7)
- #endif
-
- extern "C" double drand48();
- extern "C" void srand48(long);
-
- void clear_str (int, int);
- void message (char *, int);
- void help (int);
- inline int not_valid (int);
- int get_number (int, int);
- int bye (int);
- int ask (char * , int , int );
- int play_one_game (int , int , double * , double * , int );
- void play_many_games (int , int );
- int menu (int , char *[]);
-
- /*
- * the length of the word. will be asked before every game.
- * it is used by the class REPLY, so it has to be global. too bad...
- */
- int ln = MLN;
-
-
- /***************************************************************
- * class REPLY.
- **************************************************************/
-
- class reply {
- int b, c; // bulls & cows
- public:
- reply() { b = c = 0; };
- ~reply(){ b = c = -1;};
- void compare (int, int); // how do these numbers match?
- int match (int, int); // do these 2 numbers match?
- void output ( int, int); // put the reply at the given position
- int won() {return b == ln;};
- };
-
- int homo_guess (reply *, int *, int, int, int, int);
- int incr_guess (reply *, int *, int, int, int, int);
- int rand_guess (reply *, int *, int, int, int, int);
-
- void reply::compare (int x, int y)
- // compare x and y and put the result into the REPLY
- {
- int i, j, i10, j10;
-
- b = c = 0;
- for (i = 0, i10 = 1 ; i < ln; i++, i10 *= 10)
- for (j = 0, j10 = 1 ; j < ln; j++, j10 *= 10)
- if ((x/i10)%10 == (y/j10)%10) ( (i == j) ? (b++) : (c++) );
- }
-
- int reply::match (int x, int y)
- // check if the x and y match the REPLY
- {
- int i, j, b1, c1, i10, j10;
-
- b1 = c1 = 0;
- for (i = 0, i10 = 1 ; i < ln; i++, i10 *= 10)
- for (j = 0, j10 = 1 ; j < ln; j++, j10 *= 10)
- if ((x/i10)%10 == (y/j10)%10) ( (i == j) ? (b1++) : (c1++) );
-
- return (b1 == b)&& (c1 == c);
- }
-
- void reply::output (int x, int y)
- // put the REPLY at (x, y)
- {
- mvprintw (x, y, "b:%d c:%d", b, c);
- refresh();
- }
- // end class REPLY definition.
-
-
- /*******************************************************
- MAIN
- *******************************************************/
-
- int main (int argc, char *argv[])
- // MasterMind Player. (Byki i Korovy)
- {
- int gwon = 0, glost = 0, gtie = 0;
- time_t seed;
- #define MAIN_MENU 5
- static char * menu_lines[MAIN_MENU] =
- {"This is the Main Menu", "Play a Game of Mastermind",
- "Watch a DEMO game", "Help", "Exit"};
-
- #define PARTNER 3
- static char * partner[PARTNER] =
- {"Choose your partner", "Dumb incremental", "Smart random"};
-
- initscr(); // get the stdscr
- cbreak(); // get each character immediately
- noecho(); // no echo
- scrollok (stdscr, FALSE); // do NOT scroll
- mvprintw (0, 0, "MasterMind %s\tHELP: ", VERSION);
- srand48 (time (&seed));
- mvaddstr ( MHL, LEFTMARGIN, MINIHELP );
-
- while (1)
- {
- switch ( menu (MAIN_MENU-1, menu_lines) )
- {
- case 0:
- play_many_games (0, 1 + menu (PARTNER-1, partner ));
- break;
- case 1:
- play_many_games (1, 2);
- refresh();
- break;
- case 2:
- help (0);
- break;
- case 3:
- bye (0);
- }
- } // of while (1)
- } // of main
-
-
-
- /*******************************************************************
- interface stuff.
- defines:
- message();
- ask();
- clear_str();
- get_number();
- help();
- menu();
- bye();
- *******************************************************************/
-
- void message (char * text, int bell)
- // write the message; ring the bell.
- {
- int x, y;
-
- getyx (stdscr, y, x);
- CLN_STR(MSGL);
- mvaddstr ( MSGL, LEFTMARGIN, text );
- #ifdef __NCURSES_H
- if (bell) beep();
- #endif
- #ifdef _CURSES_H
- if (bell) BEEP;
- #endif
- move (y, x);
- refresh();
- return;
- }
-
- int ask (char * text, int bell, int def)
- // ask a question
- {
- int x, y, ans;
-
- getyx (stdscr, y, x);
- CLN_STR(ASKL);
- mvaddstr ( ASKL, LEFTMARGIN, text );
- #ifdef __NCURSES_H
- if (bell) beep();
- #endif
- #ifdef _CURSES_H
- if (bell) BEEP;
- #endif
- addstr ( (def == 0) ? " (n)..." : " (y)..." );
- refresh();
- ans = tolower (getch());
- ans = ( ans =='y' ) || ( (def) && (ans != 'n') );
- addstr ( (ans) ? "Yes." : "No.");
- move (y, x);
- refresh();
- return (ans);
- }
-
- void clear_str (int beg, int end)
- // clear the specified area.
- {
- int x, y, i;
-
- getyx (stdscr, y, x);
- for (i = beg; i <= end; i++) CLN_STR(i);
- move (y, x);
- refresh();
- return;
- }
-
- int get_number (int x, int y)
- // get an ln-digit number in_num at position (x, y).
- {
- int in_num = 0, pos = 0, c, i, flag;
- int entered[MLN];
-
- for (i = 0; i < ln; i++) entered[i] = 10;
- move (x, y);
- refresh();
- while (1)
- {
- switch (c = tolower (getch()))
- {
- case ',': case 2: /* ^B */ case 'b':
- case 'p': case 16: /* ^P */ case '<':
- MOVE_LEFT;
- break;
- case '.': case 6: /* ^F */ case 'f':
- case 'n': case 14: /* ^N */ case '>':
- MOVE_RIGHT;
- break;
- case 1: /* ^A */ case 'a':
- MOVE_HOME_LEFT;
- break;
- case 5: /* ^E */ case 'e':
- MOVE_END_RIGHT;
- break;
- case 27: /* ESC */
- switch (tolower (getch()))
- {
- case 'o': case 91: /* [ */
- switch (tolower (getch()))
- {
- case 'a': case 'd':
- MOVE_LEFT;
- break;
- case 'b': case 'c':
- MOVE_RIGHT;
- break;
- case '7': /* home */
- MOVE_HOME_LEFT;
- getch();
- break;
- case '8': /* end */
- MOVE_END_RIGHT;
- getch();
- break;
- default:
- while (getch()!='~');
- GET_HELP(1);
- }
- break;
- default:
- GET_HELP(1);
- }
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- for (i = 0; (i < ln) && ( (c-'0') != entered[i]) ; i++);
- if ( ( (c-'0') == entered[i]) && (i != ln) )
- message ("You already have this digit!", 1);
- else
- {
- entered[pos] = c-'0';
- addch (c);
- MOVE_RIGHT;
- }
- break;
- case 'h': case '?':
- GET_HELP(1);
- case 127: /* ^? */ case 8: /* ^H */
- MOVE_LEFT;
- case 32:
- addch ('*'); entered[pos] = 10; move (x, y+pos); break;
- case 10: // Enter
- for (in_num = i = 0, flag = 1; (i < ln) && (flag) ; i++)
- if (entered[i] == 10) flag = 0;
- else in_num = in_num*10+entered[i];
- if (flag)
- {
- CLN_STR(MSGL);
- return (in_num);
- }
- else
- {
- in_num = 0;
- message ("You have not entered the number yet!", 1);
- }
- break;
- case 'q': case 'x': case 3: /* ^C */
- if (ask ("Are you sure you want to quit?", 0, 0)) return (-1);
- case 12: /* ^L */ case 18: /* ^R */
- // redrawln (stdscr, 0, 24); break;
- message ("sorry, cannot redraw screen yet", 1); break;
- default:
- message ("Illegal key. Please use \"h\" or \"?\" for help.", 1);
- break;
- }
- refresh();
- } // end of while (1)
- } // get_number
-
- void help (int num)
- /*******************************************
- give help according to the context:
- 0: general;
- 1: get_number;
- 2: license;
- 3: send e-mail to the author;
- then return to the initial position of the cursor.
- *******************************************/
- {
- int x, y;
-
- getyx (curscr, x, y);
- clear_str (HLPL, MHL);
- mvaddstr ( MHL, 0, "G - general help; also: N; L; M." );
- switch (num)
- {
- case 0:
- clear_str (HLPL, HLPL+HLPLEN);
- mvaddstr ( HLPL, 0, "\tHELP: General:\n\t\
- This is a game. You and I think of a number, and each tries\n\t\
- to guess the number of the other. The answer is displayed\n\t\
- to the right in the form: \"b:2 c:1\". This means that\n\t\
- the number to the left has 3 common digits with the number\n\t\
- being guessed, 2 of them on the right position and one on\n\t\
- on the wrong.");
- message ("Press any key to continue...", 0);
- getch();
- clear_str (HLPL+1, HLPL+HLPLEN);
- mvaddstr ( HLPL+1, 0 , "\t\
- More help: N - how to enter a number; L - see the license;\n\t\
- M - send mail to the author.\n\t\
- Beware: sending mail will terminate the program!\n\t\
- G - see the general help again.");
- refresh();
- CLN_STR(MSGL);
- break;
- case 1:
- clear_str (HLPL, HLPL+HLPLEN);
- mvaddstr ( HLPL, 0 , "\tHELP: Entering a number:\n\t\
- You should enter a \"valid\" number.\n\t\
- A number is \"valid\" if it contains digits \'0\' to \'9\'\n\t\
- and does not have the same digit twice. The number can\n\t\
- start with 0. Use the space bar to erase the curent digit,\n\t\
- and the <,b, and >,f keys to move within the allotted space.\n\t\
- You can use the BS/DEL keys. The arrows should also work.");
- refresh();
- break;
- case 2:
- clear_str (HLPL, HLPL+HLPLEN);
- mvaddstr ( HLPL, 0, "\tHELP: License information:\n\t\
- Copyright (C) 1994 by Sam Shteingold, <shteingd@math.ucla.edu>\n\t\
- Comments, suggestions, bug reports/fixes are welcome!\n\t\
- This program is free software; you can redistribute it and/or modify\n\t\
- it under the terms of the GNU General Public License as published by\n\t\
- the Free Software Foundation; either version 2, or (at your option)\n\t\
- any later version.");
- message ("Press any key to continue...", 0);
- getch();
- clear_str (HLPL+1, HLPL+HLPLEN);
- mvaddstr ( HLPL+1, 0, "\t\
- This program is distributed in the hope that it will be useful, but\n\t\
- WITHOUT ANY WARRANTY; without even the implied warranty of\n\t\
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n\t\
- General Public License for more details.\n\t\
- You should have received a copy of the GNU General Public License\n\t\
- along with This program; see the file COPYING. If not, write to the\n\t\
- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.");
- refresh();
- CLN_STR(MSGL);
- break;
- case 3:
- nocbreak();
- echo();
- clear ();
- mvaddstr (0,0, "Enter the message. Terminate by a single dot on the line.\n");
- refresh();
- system ("mail shteingd@math.ucla.edu -s \"I use mastermind...\"");
- // cbreak(); noecho(); redrawwin (stdscr); break;
- bye (0);
- } // of switch (num);
- switch (tolower (getch()))
- {
- case 'g':
- help (0); break;
- case 'n':
- help (1); break;
- case 'l':
- help (2); break;
- case 'm':
- help (3); break;
- default:
- clear_str (HLPL, LINES);
- mvaddstr (MHL, LEFTMARGIN, MINIHELP);
- }
- move (x, y);
- refresh();
- return;
- } // help
-
- int menu (int num, char * items[])
- // chose an item in the menu
- // num items; items[0] = title; others - lables of the items
- {
- int pos = 0, c, i;
-
- clear_str (1, MSGL);
- PUT_HELP(items[0]);
- for (i = 1; i <= num; i++)
- mvprintw (i + STARTL - 1 , LEFTMARGIN, "%d. %s", i, items[i]);
- move (STARTL, LEFTMARGIN);
- refresh();
- while (1)
- {
- switch (c = tolower (getch()))
- {
- case ',': case 16: /* ^P */ case 2: /* ^B */ case 'b': case 'p':
- case 'k': case 127: /* ^? */ case 8: /* ^H */ case '<':
- MOVE_UP; break;
- case '.': case 14: /* ^N */ case 6: /* ^F */ case 'f': case 'n':
- case 'j': case 32: /* SP */ case '>':
- MOVE_DOWN; break;
- case 1: /* ^A */ case 'a':
- MOVE_HOME_UP; break;
- case 5: /* ^E */ case 'e':
- MOVE_END_DOWN; break;
- case 27: /* ESC */
- switch (tolower (getch()))
- {
- case 'o': case 91: /* [ */
- switch (tolower (getch()))
- {
- case 'a': /* ^ */ case 'd': /* < */
- MOVE_UP;
- break;
- case 'b': /* > */ case 'c': /* v */
- MOVE_DOWN;
- break;
- case '7': /* home */
- MOVE_HOME_UP;
- getch();
- break;
- case '8': /* end */
- MOVE_END_DOWN;
- getch();
- break;
- default:
- while (getch() != '~');
- GET_HELP(0);
- }
- break;
- default:
- GET_HELP(0);
- }
- break;
- case 'h': case '?':
- GET_HELP(0);
- case 10: // Enter
- return (pos);
- case 'q': case 'x': case 3: /* ^C */
- bye (0);
- case 12: /* ^L */ case 18: /* ^R */
- //redrawln (stdscr, 0, 24); break;
- message ("sorry, cannot redraw screen yet", 1);
- break;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (c-'1' < num) return (c-'1');
- default:
- message ("Illegal key. Please use \"h\" or \"?\" for help.", 1);
- break;
- }
- refresh();
- }
- } // menu
-
- int bye (int i)
- {
- CLN_STR(LINES-1);
- nocbreak();
- echo();
- move (LINES-1, 0);
- refresh();
- endwin();
- exit (i);
- }
-
- // end of interface
-
-
- /*******************************************************************
- algorithm only. Uses:
- message();
- get_number().
- ask();
- *******************************************************************/
-
- int play_one_game (int first, int second, double * f_tm, double * s_tm,
- int max_num)
- /**************
- play Mastermind just once.
- first/second:
- 0: human; first AND second cannot be 0 BOTH at the same time;
- 1: computer, incremental;
- 2: computer, random.
- returns:
- 0: tie;
- 1: first won;
- -1: second won;
- 10: error.
- **************/
- {
- struct timeval tm1, tm2;
- struct timezone tzp;
- int frs_num, sec_num, round;
- reply frs_reps[GL], sec_reps[GL];
- int frs_ask[GL], sec_ask[GL];
- int (*frs_get) (reply *, int *, int, int, int, int);
- int (*sec_get) (reply *, int *, int, int, int, int);
-
- #define NUMLN 5
- static char * lines[NUMLN] = {"Are you still there?! You are very daring!",
- "No result yet, but somehow I'm sure I'll win.",
- "You think slowly. I bet you are a mere human!",
- "Your case is hopeless. Surrender!",
- "Why don\'t you just give up?!"};
-
- if ( (first == 0) && (second == 0))
- {
- message ("both cannot be humans!", 1);
- return 10;
- }
-
- clear_str (STARTL, MSGL-1);
-
- // the framework:
- switch (first)
- {
- case 0:
- mvaddstr (STARTL, FIRST-BSPACE, "1:Human - #:");
- mvaddstr (STARTL+1, SECOND-BSPACE, " H guesses:");
- frs_get = & homo_guess;
- break;
- case 1:
- mvaddstr (STARTL, FIRST-BSPACE, "1:CIncr - #:");
- mvaddstr (STARTL+1, SECOND-BSPACE, " CI guesses:");
- frs_get = & incr_guess;
- break;
- case 2:
- mvaddstr ( STARTL, FIRST-BSPACE, "1:CRand - #:");
- mvaddstr ( STARTL+1, SECOND-BSPACE, " CR guesses:");
- frs_get = & rand_guess;
- break;
- default:
- message ("wrong first argument in play_one_game. hit a key\t\t", 1);
- getch();
- return (10);
- }
- PUT_STARS(STARTL, FIRST)
- switch (second)
- {
- case 0:
- mvaddstr (STARTL, SECOND-BSPACE, "2:Human - #:");
- mvaddstr (STARTL+1, FIRST-BSPACE, " H guesses:");
- sec_get = & homo_guess;
- break;
- case 1:
- mvaddstr (STARTL, SECOND-BSPACE, "2:CIncr - #:");
- mvaddstr (STARTL+1, FIRST-BSPACE, " CI guesses:");
- sec_get = & incr_guess;
- break;
- case 2:
- mvaddstr (STARTL, SECOND-BSPACE, "2:CRand - #:");
- mvaddstr (STARTL+1, FIRST-BSPACE, " CR guesses:");
- sec_get = & rand_guess;
- break;
- default:
- message ("wrong second argument in play_one_game. hit a key\t\t", 1);
- getch();
- return (10);
- }
- PUT_STARS (STARTL, SECOND)
-
- // get the numbers to be guessed.
- if (first)
- {
- do frs_num = RND(max_num);
- while (not_valid (frs_num));
- }
- else
- {
- PUT_HELP("Enter your secret number, then press <Enter>.");
- if ( (frs_num = get_number (STARTL, FIRST)) == -1) return (10);
- }
- if (second)
- {
- do sec_num = RND(max_num);
- while (not_valid (sec_num));
- }
- else
- {
- PUT_HELP("Enter your secret number, then press <Enter>.");
- if ( (sec_num = get_number (STARTL, SECOND)) == -1) return (10);
- }
-
- round = 0;
- do
- {
- // do the moves:
- gettimeofday(&tm1, &tzp);
- if ( ( (*frs_get) (frs_reps, frs_ask, SECOND,
- round, max_num, sec_num)) == -1)
- return (10);
- gettimeofday(&tm2, &tzp);
- *f_tm += (double) (tm2.tv_sec - tm1.tv_sec) +
- ( (double) (tm2.tv_usec - tm1.tv_usec) )/1000000;
- refresh();
-
- gettimeofday(&tm2, &tzp);
- if ( ( (*sec_get) (sec_reps, sec_ask, FIRST ,
- round, max_num, frs_num)) == -1)
- return (10);
- gettimeofday(&tm2, &tzp);
- *s_tm += (double) (tm2.tv_sec - tm1.tv_sec) +
- ( (double) (tm2.tv_usec - tm1.tv_usec) ) /1000000;
- refresh();
-
- // the results of the round:
- if ( (frs_reps[round].won())&& (sec_reps[round].won())) return (0); //tie
- else if ( (! (frs_reps[round].won()))&& (sec_reps[round].won()))
- {
- mvprintw ( STARTL, SECOND, "%.*d", ln, sec_num);
- refresh();
- return (-1);
- }
- else if ( (frs_reps[round].won())&& (! (sec_reps[round].won())))
- {
- mvprintw (STARTL, FIRST, "%.*d", ln, frs_num);
- refresh();
- return (1);
- }
- else if (! (first*second)) message (lines[RND(NUMLN)], 0);
- }
- while (round++ < GL);
- } // of play_one_game
-
- int rand_guess (reply reps[GL], int old_guess[GL], int pos,
- int round, int max_num, int secret)
- /********
- make a random guess of SECRET, which is up to MAX_NUM; put at collumn POS.
- use old guesses OLD_GUESS with replies REPS in ROUND.
- ********/
- {
- int j, i, ini, num_ok = 0;
-
- ini = RND(max_num);
- PUT_STARS(STARTL+1+round, pos)
- message ("CRand is thinking. Please wait...", 0);
- if (drand48() > 0.5)
- { // go up
- for (i = ini+1; (i != ini) && (!num_ok) ; i = ( i + 1 ) % max_num )
- if (!not_valid (i))
- for (j = 0, num_ok = 1 ; (j < round) && (num_ok) ; j++)
- num_ok *= reps[j].match (i, old_guess[j]);
- old_guess[round] = ( i - 1 + max_num ) % max_num;
- }
- else
- { // go down
- for (i = ini-1; (i != ini) && (!num_ok) ; i = ( i - 1 + max_num ) % max_num )
- if (!not_valid (i))
- for (j = 0, num_ok = 1 ; (j < round) && (num_ok) ; j++)
- num_ok *= reps[j].match (i, old_guess[j]);
- old_guess[round] = ( i + 1 ) % max_num;
- }
- if (i == ini) { message ("Random: ERROR! hit a key", 1); getch(); }
- mvprintw (STARTL+1+round, pos, "%.*d", ln, old_guess[round]);
- reps[round].compare (old_guess[round], secret);
- reps[round].output (STARTL+1+round, pos+SPACE);
- return (old_guess[round]);
- } // rand_guess
-
- int incr_guess (reply reps[GL], int old_guess[GL], int pos,
- int round, int max_num, int secret)
- /*****
- make an incremental guess of SECRET, which is up to MAX_NUM; put at
- collumn POS. use old guesses OLD_GUESS with replies REPS in ROUND.
- *****/
- {
- int j, i, ini, num_ok = 0;
-
- PUT_STARS(STARTL+1+round, pos)
- message ("CIncr is thinking. Please wait...", 0);
- (round) ? (i = old_guess[round-1]) : (i = 0);
- for (i++, num_ok = 0; (i < max_num) && (!num_ok); i++)
- if (!not_valid (i))
- for (j = 0, num_ok = 1; (j < round) && (num_ok) ; j++)
- num_ok *= reps[j].match (i, old_guess[j]);
- if (i == max_num) { message ("Incremental: ERROR! hit a key", 1); getch(); }
- old_guess[round] = --i;
- mvprintw (STARTL+1+round, pos, "%.*d", ln, old_guess[round]);
- reps[round].compare (old_guess[round], secret);
- reps[round].output (STARTL+1+round, pos+SPACE);
- return (old_guess[round]);
- } // incr_guess
-
- int homo_guess (reply reps[GL], int old_guess[GL], int pos,
- int round, int max_num, int secret)
- // get the human player's guess.
- {
- PUT_STARS(STARTL+1+round, pos)
- PUT_HELP("Enter your guess, then press <Enter>.");
- old_guess[round] = get_number (STARTL+1+round, pos);
- reps[round].compare (old_guess[round], secret);
- reps[round].output (STARTL+1+round, pos+SPACE);
- return (old_guess[round]);
- }
-
- void play_many_games (int f, int s)
- // play several games, keeping the score.
- {
- int first = 0, second = 0, tie = 0, i;
- int max_num = 1; // 10^ln
- double f_tm = 0, s_tm = 0;
-
- // get ln:
- PUT_HELP ("What will the length of the number be?");
- clear_str (STARTL, MSGL);
- mvaddstr (HLPL, 0, "\tPlease enter the length of the word.\n\t\
- You should enter a reasonable number:\n\t\
- 2 is too short - it won't be interesting, \n\t\
- 6 is too long - it'll take me too long\n\t\
- to produce each guess.\n\t\
- The reasonable number is, probably, 4, \n\t\
- but 3 also might be interesting.");
- mvprintw ( MSGL, LEFTMARGIN,
- "Enter number from 2 to %d. Default is %d ...", MLN, DEFLN );
- refresh();
- ln = getch() - '0';
- if ( (ln < 2) || (ln > MLN)) ln = DEFLN;
- clear_str (HLPL, MSGL);
- // if not a demo, get_number will say something...
- PUT_HELP("Demo game...");
-
- // initialization of 'max_num'.
- for (i = 0; i < ln; i++) max_num *= 10;
-
- do
- {
- switch (play_one_game (f, s, & f_tm, & s_tm, max_num))
- {
- case 0 :
- if (f*s == 0) PUT_HELP ("Uphhh... Tie! That was close!");
- tie++ ; break;
- case 1 :
- if (f == 0) PUT_HELP ("Ouch! You are SMART! You beat me!");
- if (s == 0) PUT_HELP ("As one could expect, you lost.");
- first++; break;
- case -1:
- if (s == 0) PUT_HELP ("Ouch! You are SMART! You beat me!");
- if (f == 0) PUT_HELP ("As one could expect, you lost.");
- second++; break;
- }
- mvprintw (1, 1, "1:%d; 2:%d; tie:%d; games:%d; time: 1:%.3f sec; 2:%.3f sec.",
- first, second, tie, first+second+tie, f_tm, s_tm);
- mvprintw (STARTL, FIRST + SPACE, "(won: %d)", first);
- mvprintw (STARTL, SECOND + SPACE, "(won: %d)", second);
- }
- while (ask ("The game is over. Again?", 0, 1));
- clear_str (STARTL-1, MSGL);
- } // play_many_games
-
- inline int not_valid (int x)
- /***************************************
- Check if the number 'x' is valid. Return 0 if valid; or the second
- part or the first bad spot: for number 4598595 returns 4 - the
- position of the second "5".
- To save time does NOT check x < 10^ln. BEWARE!
- ***************************************/
- {
- int i, j, i10, j10;
-
- for (i = 1, i10 = 10 ; i < ln; i++, i10 *= 10)
- for (j = 0, j10 = 1 ; j < i; j++, j10 *= 10)
- if ( (x/i10)%10 == (x/j10)%10 ) return (i);
- return (0);
- }
-